package com.qunar.train.mock.config;

import com.qunar.train.mock.util.AegisLog;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import qunar.tc.qconfig.client.spring.QConfig;

public class AegisQconfigProcessor implements BeanFactoryPostProcessor {

    private static String resourcesPath = Class.class.getClass().getResource("/").getPath().split("/target")[0] + "/src/test/resources/" + "qconfig_test/";
    private static String qconfigTargetDir = Class.class.getClass().getResource("/").getPath().split("/target")[0] + "/target/test-classes/" + "qconfig_test/";
    private static volatile List<String> classNames = new ArrayList<>(256);

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        Map<String, BeanDefinition> map = getField(configurableListableBeanFactory, "beanDefinitionMap");
        for (Map.Entry<String, BeanDefinition> entry : map.entrySet()) {
            String className = entry.getValue().getBeanClassName();
            classNames.add(className);
        }
        run();
    }

    public void run() {
        Runnable runnable = new Runnable() {
            public void run() {
                for (String className : classNames) {
                    handleclass(className);
                }
            }
        };
        runnable.run();
    }

    private void handleclass(String className) {
        if (className != null) {
            Class clazz = null;
            try {
                if (className.endsWith("Controller") || className.endsWith("Invoke") || className.endsWith("Logic") || className.endsWith("EnvUtil") || className.endsWith("Service") || className.contains("Sedis") || className.contains("Redis") || className.endsWith("SpringUtil") || className.contains("Mock") || className.endsWith("SpringContextUtils")|| className.endsWith("SelfAgentAccountDiffJob")){
                    return;
                } else {
                    clazz = Class.forName(className);
                    if (clazz.isAnnotationPresent(Service.class) || clazz.isAnnotationPresent(Controller.class) || clazz.isAnnotationPresent(Component.class) || clazz.isAnnotationPresent(Repository.class)) {
                        handleField(clazz);
                        handleMethod(clazz);
                    }
                }
            } catch (ClassNotFoundException e) {
                AegisLog.error(className + " 未找到该类 " + e);
            } catch (ExceptionInInitializerError f) {
                AegisLog.error(className + " 初始化失败 " + f);
            }
        }
    }

    public static Map<String, BeanDefinition> getField(Object obj, String fieldName) {
        Map<String, BeanDefinition> map = null;
        try {
            Class<?> clazz = obj.getClass();
            Field field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            if (field != null) {
                //修改静态属性值
                map = (Map<String, BeanDefinition>) field.get(obj);
            }
        } catch (Exception e) {
            AegisLog.error(e);
        }
        return map;
    }

    public static void handleField(Class<?> clazz) {
        Field[] fileds = clazz.getDeclaredFields();
        for (Field field : fileds) {
            if (field.isAnnotationPresent(QConfig.class)) {
                QConfig qConfig = field.getAnnotation(QConfig.class);
                String qcofigFileName = qConfig.value();
//                AegisLog.info(qcofigFileName);
                touchNonExistFiles(qcofigFileName);
            }
        }
    }

    public static void handleMethod(Class<?> clazz) {
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(QConfig.class)) {
                QConfig qConfig = method.getAnnotation(QConfig.class);
                String qcofigFileName = qConfig.value().toLowerCase();
//                AegisLog.info(qcofigFileName);
                touchNonExistFiles(qcofigFileName);
            }
        }
    }

    public static void touchNonExistFiles(String qcofigFileName) {
        File fInTestResources = new File(resourcesPath + MockQconfig.getAppCode() + "/" + qcofigFileName);
        touchNonExistFile(fInTestResources);
        File fInTestClasses = new File(qconfigTargetDir + MockQconfig.getAppCode() + "/" + qcofigFileName);
        touchNonExistFile(fInTestClasses);
    }

    public static void touchNonExistFile(File file) {
        File dic = file.getParentFile();
        if (!dic.exists()) {
            dic.mkdir();
        }
        if (!file.exists()) {
            try {
                AegisLog.log(file.getName() + "不存在，创建空文件");
                file.createNewFile();
                if (file.getName().endsWith(".json")) {
                    //如果是jsong格式的文件，添加[]
                    FileWriter fileWritter = new FileWriter(file.getPath(), false);
                    BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
                    bufferWritter.write("[]");
                    bufferWritter.close();
                    fileWritter.close();
                }
            } catch (IOException e) {
                AegisLog.error(e);
            }
        }
    }

}
